home *** CD-ROM | disk | FTP | other *** search
/ The X-Philes (2nd Revision) / The X-Philes Number 1 (1995).iso / xphiles / hp48_2 / processo.tar / processor.3 < prev   
Text File  |  1989-11-20  |  13KB  |  434 lines

  1. HOW TO ENTER AND RUN MACHINE CODE PROGRAMS
  2.  
  3.  
  4. Inline Machine Code and SYSEVAL
  5. ===============================
  6.  
  7. How do you execute machine code programs?  There are two ways.
  8. The first is to place the program at a known location in memory
  9. and jump to it using SYSEVAL.  The second is to wrap the program
  10. up as an inline machine code object (IMC).  The second approach
  11. is best because you can store an IMC in any variable or function
  12. and you don't have to be concerned about its location as it gets
  13. moved around in memory.  It also executes considerably faster.
  14.  
  15. When you first open your calculator, there is no way to create
  16. IMCs, so you have to resort to SYSEVAL at least once to start.
  17. Since we're going to be writing lots of programs, we want an
  18. easy way to enter them.  This section is an explanation of the
  19. techniques you can use.
  20.  
  21. The easiest way to create an IMC is to take an object with the
  22. same structure, such as a string, and change its type.    As an
  23. example, let us examine how the string "hello" and the following
  24. machine code program are stored in memory.
  25.  
  26.     Drop:    174    add    5,d1    ; drop top of stack
  27.         E7    inc.a    d    ; increment free stack
  28.         142    move.a    @d0,a    ;\
  29.         164    add    5,d0    ; return to system
  30.         808C    jmp    @a    ;/
  31.  
  32. The string "hello" is stored in memory as E4A20F00008656C6C6F6,
  33. while the IMC, Drop, is stored as 69C2041000174E7142164808C.
  34. The objects are structured in the following way:
  35.  
  36.     type    length    data
  37.  
  38.     02A4E    0000F    8656C6C6F6        "hello"
  39.     02C96    00014    174E7142164808C     174 E7 142 164 808C
  40.  
  41.  
  42. The type is an address that gets stored backwards.  The length
  43. of the object includes everything but the type and is also stored
  44. backwards.  Since the ASCII for "hello" is 68 65 6C 6C 6F, it is
  45. apparent that the HP stores characters with their nibbles swapped.
  46. The type and length are each 5 nibbles long, and the data part is
  47. (length - 5) nibbles long.
  48.  
  49. The next step is to create a string object that has the right
  50. data for our machine program:
  51.  
  52. ________________________________________________________________
  53.  
  54.     First let's do it manually so you understand the process.
  55.     We take the nibbles of the program two at a time, swap
  56.     they're order, convert them to characters (using CH), and
  57.     concatenate them into a string:
  58.  
  59.     CH
  60.     << B->R CHR >>
  61.  
  62.     #71 CH #E4 CH + #17 CH + #24 CH + #61 CH + #84 CH +
  63.     #80 CH + #0C CH +
  64. ________________________________________________________________
  65.  
  66.     This can be done automatically by the function HEXIFY which
  67.     takes the machine code in a string and does the conversion.
  68.  
  69.     HEXIFY [6AC9]
  70.     << "" SWAP 1 OVER SIZE
  71.     FOR j
  72.         "#" OVER j 1 + DUP SUB + OVER j j SUB + "h" +
  73.         STR-> B->R CHR ROT SWAP + SWAP 2
  74.     STEP DROP
  75.     >>
  76.  
  77.     "174E7142164808C" HEXIFY
  78. ________________________________________________________________
  79.  
  80.  
  81. Both methods yield the rather unusual string, "q..$a. .", which
  82. is represented internally as E4A2051000174E7142164808C0.  It is
  83. almost exactly what we want for our IMC object.  Since strings
  84. must have an even number of nibbles an extra zero gets added at
  85. the end of the program.  All that's left to do is make the string
  86. into an IMC by changing E4A20 to 69C20.
  87.  
  88.  
  89. Changing Object Type
  90. ====================
  91.  
  92. So now let's write a little program that will take an object on
  93. the stack and change its type:
  94.  
  95.  
  96. 143    MOVE.A    @D1,A        ; new type integer
  97. 132    SWAP    A,D0
  98. 169    ADD    10,D0
  99. 146    MOVE.A    @D0,C        ; contents of integer
  100. 132    SWAP    A,D0
  101. 174    ADD    5,D1        ; pop stack
  102. E7    INC.A    D        ; free space
  103. 143    MOVE.A    @D1,A        ; object
  104. 132    SWAP    A,D0
  105. 144    MOVE.A    C,@D0        ; set new type
  106. 132    SWAP    A,D0
  107. 142    MOVE.A    @D0,A        ;\
  108. 164    ADD    5,D0        ; return to system
  109. 808C    JUMP    @A        ;/
  110.  
  111. First we use HEXIFY to create a string with the code in it.
  112.  
  113. "143132169146132174E7143132144132142164808C" HEXIFY
  114.  
  115. resulting in:
  116.  
  117. "A.#a.d1.G~A.#A.#A.F.."
  118.  
  119. This string must now be turned into an IMC.  Since this very
  120. string contains the code to do that, we want to run it on itself.
  121. At this point, the only way to do so is with SYSEVAL.
  122.  
  123. ________________________________________________________________
  124.  
  125. First let's do it manually so you understand the process.
  126.  
  127.     To use SYSEVAL we follow these four steps.
  128.  
  129.       1.  Put the code in a known location.
  130.       2.  Put the address of this location in another location.
  131.       3.  Type in any arguments the program needs.
  132.       4.  Type in address of the second location and SYSEVAL
  133.  
  134.  
  135.     1.    The first variable in the HOME directory always goes at
  136.     the top of memory, so we'll store the code string there.
  137.     Since it is 42 nibbles long the code will begin at #CFFD6
  138.     (#D0000 - 42).
  139.  
  140.     2.    Now we need to put a copy of the address #CFFD6 somewhere.
  141.     It turns out that the most convenient place is right inside
  142.     the program just after the return.  This will make the
  143.     program 6 nibbles longer (HEXIFY pads it to an even 48) so
  144.     our address becomes #CFFD0.
  145.  
  146.       "143132169146132174E7143132144132142164808C0DFFC" HEXIFY
  147.  
  148.     results in: "A.#a.d1.G~A.#A.#A.F....."
  149.  
  150.     So to complete steps 1 and 2 type:
  151.  
  152.         HOME 'CHT' DUP PURGE STO
  153.  
  154.     3.    We are changing the program itself to an IMC so we put
  155.     these arguments on the stack:
  156.  
  157.         'CHT' RCL
  158.         #2C96
  159.  
  160.     4.    The address #CFFD0 is store just before the padding 0
  161.     at the top of memory, so we type:
  162.  
  163.         #CFFFA    SYSEVAL
  164.  
  165.     CHT is magically changed to a System Object.  Here are all
  166.     the steps summarized as a program.
  167.  
  168.     MCHT [8B0C]
  169.     <<
  170.        "143132169146132174E7143132144132142164808C0DFFC"
  171.        HEXIFY
  172.        HOME 'CHT' DUP PURGE STO
  173.        'CHT' RCL #2C96h
  174.        #CFFFAh  SYSEVAL DROP
  175.     >>
  176. ________________________________________________________________
  177.  
  178.  
  179. Caveat
  180. ======
  181.  
  182.     The CHT function is dangerous because it doesn't do any error
  183.     checking.  If you call it with the wrong arguments or too few
  184.     arguments you may lose memory.  This problem is easily solved.
  185.  
  186.     There are only 12 type conversions that will work and not all
  187.     of them make sense to do.  They are:
  188.  
  189.     string <-> #integer        list    <-> program
  190.     string <-> IMC            list    <-> algebraic
  191.     IMC    <-> #integer        program <-> algebraic
  192.  
  193.  
  194.     Here is a program that creates three useful type conversion
  195.     functions:
  196.  
  197.     MTCF [3321]
  198.     <<
  199.        << IF DUP TYPE 8 != OVER ->STR 1 1 SUB "<<" != OR
  200.           THEN ABORT END  #2A96h CHT >> 'PGM->' STO
  201.  
  202.        << IF DUP TYPE 5 != OVER 1 GET ->STR "<<" != OR
  203.           THEN ABORT END  #2C67h CHT >> '->PGM' STO
  204.  
  205.        << IF DUP TYPE 2 != THEN ABORT END
  206.           #2C96h CHT >> '->IMC' STO
  207.  
  208.        'PGM->' '->PGM' '->IMC'
  209.        1 3 START
  210.         DUP RCL
  211.         1 ->LIST LIST-> DROP
  212.         PGM-> 'CHT' DUP2 POS
  213.         SWAP RCL PUT ->PGM SWAP STO
  214.        NEXT
  215.  
  216.        'CHT' PURGE
  217.     >>
  218.  
  219.     What we end up with are the following functions:
  220.  
  221.     ->ICM     converts a string to inline machine code
  222.     PGM->     converts a program to a list
  223.     ->PGM     converts a list to a program
  224.  
  225. We need all three of these to write a function that makes machine
  226. code programming practically effortless.
  227.  
  228.  
  229. Simple Machine Code Programming with PGM
  230. ========================================
  231.  
  232.  
  233.     PGM [71C6]
  234.     <<
  235.     1 + OVER PGM-> SWAP DUP2 GET HEXIFY ->IMC
  236.     PUT ->PGM SWAP ->PGM DROP
  237.     >>
  238.  
  239.  
  240. Here is an example of using PGM to create a peek program:
  241.  
  242.     PIGT [4919]
  243.     <<
  244.        RCWS SWAP 64 STWS #0h OR SWAP STWS
  245.        "13210314313016914613615671301691547113132142164808C"
  246.     >>
  247.  
  248.  
  249. 'PIGT' RCL 9 PGM 'PIG' STO
  250.  
  251.  
  252. The arguments to PGM are a program and the position in the program
  253. of the machine code string, in this case the 9th position.  This
  254. technique doesn't work if the string is inside an IF, a loop, or
  255. another set of << >> brackets.    If you need to put other stuff
  256. before an IMC in a program, I recommend doing only the minimum
  257. necessary to check and prepare arguments for the IMC.
  258.  
  259. ================================================================
  260.  
  261.  
  262.     STYLE CONVENTIONS FOR HP28S MACHINE CODE
  263.  
  264.  
  265. As in writing, use blank lines to divide your code into paragraphs
  266. that express a single thought.    As in writing, if a paragraph gets
  267. too long, break it up to increase the amount of white space.  Set
  268. labels apart and make them descriptive.  Just as footnotes* are more
  269. effective than parentheses, documentation is more effective than
  270. inline comments.
  271.  
  272. I recommend that you type programs entirely in lower case, except
  273. for labels, hex constants, and comments.  Hex constants should be
  274. typed in upper case, and labels in mixed or all upper case.  If a
  275. comment is close to being a sentence, capitalize the first letter
  276. and end the comment with a period.
  277.  
  278. Certain forms of some instructions (marked with ***) have default
  279. field specifiers.  I suggest you omit the field suffix in these
  280. cases.    Instructions without a default should always be written
  281. with a field suffix.  In cases where there could be confusion, you
  282. might as well put the suffix on all instructions.
  283.  
  284. At the moment, we have no assembler program to ensure that your
  285. source corresponds to its machine code or to enforce the syntax
  286. rules of instructions.    That is why I have made these rules as
  287. simple as possible.  When I get time, I will write an assembler.
  288.  
  289. When you are publishing programs, I recommend that you align the
  290. parts of each instruction on successive eight character tabs:
  291.  
  292. Hex    Name.f    Args        Comments
  293.  
  294. 33A0D0    move.p4 #0D0A,c     ; CR/LF characters
  295.  
  296. ________________________________________________________________
  297.  
  298.   *
  299.     Too many parenthesized comments in text can destroy both
  300.     readability and understanding.  Footnotes are less obtrusive
  301.     and provide more leeway for comprehensive explanation.  In
  302.     similar fashion, inline comments distract from the code and
  303.     are so small they don't explain much. Do not, as I have seen,
  304.     comment every line with a restatement of what the assembler
  305.     instruction is doing. Do comment what you put into registers.
  306.     The actions of a program are better understood at the level
  307.     of functions and high level control constructs, such as loops
  308.     and ifs.  I have commented every line of my sample programs
  309.     only because their purpose is to teach the instruction set.
  310. ________________________________________________________________
  311.  
  312. Another sample program:
  313.  
  314. I wanted to write a really fast program to find bit patterns in
  315. memory.  Most processors perform register operations much more
  316. quickly than memory operations, because the memory bus is slower
  317. than the internal bus.    With even a minimal amount of caching or
  318. pipelining (e.g., prefetch) this difference is quite sizable.
  319.  
  320. With that in mind, I designed the following program to minimize
  321. memory operations.  It turns out only about 10% faster than the
  322. brute force approach.  One reason is that the speed it gains in
  323. minimizing memory reads is partially lost in the more complicated
  324. loop structure.  This small improvement is probably not worth the
  325. added complexity, but it is an interesting program to read:
  326.  
  327.      Find:
  328.  
  329. 132    swap    a,d0        ;\
  330. 120    swap    a,r0        ; save d0 and b
  331. AFC    swap.w    a,b        ;
  332. 121    swap    a,r1        ;/
  333.  
  334.  
  335. 174    add    5,d1        ;\
  336. 147    move.a    @d1,c        ;
  337. 134    move    c,d0        ; put value in b
  338. 16A    add    11,d0        ;
  339. 1567    move.w    @d0,c        ;
  340. AF5    move.w    c,b        ;/
  341.  
  342. 180    sub    1,d0        ;\
  343. 1564    move.s    @d0,c        ; put number of nibbles (-1) in c(s)
  344. 1C4    sub    5,d1        ;/
  345.  
  346.  
  347. 143    move.a    @d1,a        ;\
  348. 130    move    a,d0        ;
  349. 169    add    10,d0        ; put starting address in d0
  350. 142    move.a    @d0,a        ;
  351. 130    move    a,d0        ;/
  352.  
  353.      Fetchloop:
  354.  
  355. 1527    move.w    @d0,a        ; get next word
  356. 80DF    move    c,15,p        ; put length in p
  357.  
  358.      Panloop:
  359.  
  360. 91052    breq.wp a,b,Found    ; full length match!
  361. 160    add    1,d0        ;\
  362. BF4    srn.w    a        ; shift alignment one nibble
  363. B46    inc.s    c        ;/
  364. 51F    brcc    Panloop     ;
  365.  
  366. 80CF    move    p,c,15        ; put length in c
  367.  
  368.      Zoomloop:
  369.  
  370. 0D    dec    p        ; one less nibble to match against
  371. 40E    brcs    Fetchloop    ; no more nibbles left
  372. 910BD    breq.wp a,b,Fetchloop    ; partial match
  373. BF4    srn.w    a        ;
  374. 160    add    1,d0        ;
  375. 5FE    brcc    Zoomloop    ;-exit if we have wrapped memory
  376.  
  377.      Found:
  378.  
  379. 143    move.a    @d1,a        ;\
  380. 132    swap    a,d0        ;
  381. 169    add    10,d0        ; replace starting address with d0
  382. 140    move.a    a,@d0        ;/
  383.  
  384. 20    move    0,p        ; restore p
  385.  
  386. 121    swap    a,r1        ;\
  387. AFC    swap.w    a,b        ; restore b and d0
  388. 120    swap    a,r0        ;
  389. 132    swap    a,d0        ;/
  390.  
  391. 142    move.a    @d0,a        ;\
  392. 164    add    5,d0        ; return to system
  393. 808C    jump    @a        ;/
  394.  
  395.  
  396.  
  397.     FINDT [8AD6]
  398.     << RCWS 20 STWS SWAP #0h OR SWAP STWS
  399.     "132120AFC12117414713416A1567AF518015641C414313
  400.     0169142130152780DF91052160BF4B4651F80CF0D40E910
  401.     BDBF41605FE14313216914020121AFC120132142164808C"
  402.     1 +
  403.     >>
  404.  
  405.  
  406.     then type 'FINDT' RCL 9 PGM 'FIND' STO
  407.  
  408.     yielding:
  409.  
  410.     << RCWS 20 STWS SWAP #0h OR SWAP STWS
  411.        System Object 1 +>>
  412.  
  413.  
  414. The way you use this program is to specify a memory pattern and a
  415. place to start looking.  A memory pattern is a sequence of up to 15
  416. nibbles and a one nibble length (1-the number of nibbles in the
  417. pattern).
  418.  
  419. For, instance if you want to find instances of the instruction
  420. 808C in memory, you can type:
  421.  
  422.     #C8083 #0 FIND  That way you can just keep
  423. hitting FIND to get subsequent instances.  This version doesn't stop
  424. until it finds an instance or scans the entire address space.
  425.  
  426. ________________________________________________________________
  427.  
  428. Good luck!
  429.  
  430. Alonzo Gariepy
  431. alonzo@microsoft
  432.  
  433.  
  434.